package com.tianyu.inspection.service.websocket;

import com.alibaba.fastjson2.JSONObject;
import com.tianyu.inspection.common.enums.RoState;
import com.tianyu.inspection.common.enums.WebSocketMessageType;
import com.tianyu.inspection.common.protobuf.Telemetry;
import com.tianyu.inspection.entity.Danger;
import com.tianyu.inspection.entity.model.WebSocketChannelMo;
import com.tianyu.inspection.entity.vo.WebSocketRo;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.ocs.model.OcsSimpleModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.ui.ModelMap;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import static com.tianyu.inspection.service.websocket.server.WebSocketServer.WEB_SOCKET_CHANNEL_MAP;


/**********************************
 * @Author YSW
 * @Description
 * @Date 2020.12.21 - 12:21
 **********************************/

@Slf4j
@Component
public class WebSocketService {

    @Resource
    private OcsSimpleModel ocsSimpleModel;

    /**
     * 向所有同项目下在线客户端发送实时遥测信息
     *
     * @param data
     */
    public void sendTelemetryMessage(final Telemetry.LiveData data) {
        for (Map.Entry<Integer, WebSocketChannelMo> entry : WEB_SOCKET_CHANNEL_MAP.entrySet()) {
            WebSocketChannelMo webSocketChannelMo = entry.getValue();
            if (data.getProjectId() == webSocketChannelMo.getProjectId() || webSocketChannelMo.getProjectId() == 0) {
                log.debug("{}任务[{}] webSocket 推出实时遥测数据 -> 用户Id[{}]", data.getSource(), data.getTaskId(), webSocketChannelMo.getUserId());
                ByteBuf buffer = webSocketChannelMo.getChannel().alloc().directBuffer();
                buffer.writeBytes(data.toByteArray());
                webSocketChannelMo.getChannel().writeAndFlush(new BinaryWebSocketFrame(buffer));
            }
        }
    }

    /**
     * 飞行任务状态实时推送
     *
     * @param source
     * @param flyTaskId
     * @param status
     * @param uavId
     * @param uavName
     */
    public void sendAdminFlyTaskStatus(Integer source, Integer projectId, String flyTaskId, Integer status, String uavId, String uavName) {
        final JSONObject jsonObject = new JSONObject();
        //来源 1 云平台 2 御空
        jsonObject.put("source", source);
        //所属项目
        jsonObject.put("projectId", projectId);
        //任务编号
        jsonObject.put("taskNumber", flyTaskId);
        //任务状态 1 任务开始 2 任务结束 3 开始推流 4 结束推流 5 视频存储完成
        jsonObject.put("status", status);
        jsonObject.put("uavId", uavId);
        jsonObject.put("uavName", uavName);
        sendAdminMessage(WebSocketMessageType.WS_TASK_STATUS, jsonObject);
    }

    public void sendAdminMessage(WebSocketMessageType type, Object o) {
        for (Map.Entry<Integer, WebSocketChannelMo> entry : WEB_SOCKET_CHANNEL_MAP.entrySet()) {
            WebSocketChannelMo webSocketChannelMo = entry.getValue();
            if (webSocketChannelMo.getProjectId() == 0) {
                WebSocketRo<Object> webSocketRo = new WebSocketRo<>();
                webSocketRo.setMessageType(type.getValue());
                webSocketRo.setContent(o);
                String replyMessage = JSONObject.toJSONString(webSocketRo);
                webSocketChannelMo.getChannel().writeAndFlush(new TextWebSocketFrame(replyMessage));
            }
        }
    }

    /**
     * 向企业管理员、企业普通用户、巡线员发送实时添加的险情信息
     *
     * @param danger
     */
    public void sendDangerMessage(final Danger danger) {
        danger.setInspectors(null);
        danger.setStatus(null);
        if (Objects.nonNull(danger.getLabelImage())) {
            danger.setLabelImage(ocsSimpleModel.getObjectUrl(danger.getLabelImage()));
        }
        for (Map.Entry<Integer, WebSocketChannelMo> entry : WEB_SOCKET_CHANNEL_MAP.entrySet()) {
            WebSocketChannelMo webSocketChannelMo = entry.getValue();
            if (danger.getProjectId().equals(webSocketChannelMo.getProjectId()) || webSocketChannelMo.getProjectId() == 0) {
                if (webSocketChannelMo.getRoleId() <= 3) {
                    log.info("WebSocket 推出实时险情标记数据 -> 用户[{}]", webSocketChannelMo.getUserId());
                    WebSocketRo<Danger> webSocketRo = new WebSocketRo<>();
                    webSocketRo.setMessageType(WebSocketMessageType.WS_DANGER_LABEL.getValue());
                    webSocketRo.setContent(danger);
                    webSocketRo.setState(RoState.WEBSOCKET_SUCCESS.getValue());
                    String replyMessage = JSONObject.toJSONString(webSocketRo);
                    webSocketChannelMo.getChannel().writeAndFlush(new TextWebSocketFrame(replyMessage));
                }
            }
        }
    }

    /**
     * 向企业管理员、企业普通用户、巡线员发送实时添加的险情信息
     */
    public void sendUserPositionMessage(final JSONObject positionMessage, Integer projectId) {
        for (Map.Entry<Integer, WebSocketChannelMo> entry : WEB_SOCKET_CHANNEL_MAP.entrySet()) {
            WebSocketChannelMo webSocketChannelMo = entry.getValue();
            if (webSocketChannelMo.getProjectId().equals(projectId) || webSocketChannelMo.getProjectId() == 0) {
                if (webSocketChannelMo.getRoleId() <= 3) {

                    log.info("WebSocket 推出巡线员实时位置数据 -> 用户[{}]", webSocketChannelMo.getUserId());
                    WebSocketRo<JSONObject> webSocketRo = new WebSocketRo<>();
                    webSocketRo.setMessageType(WebSocketMessageType.WS_USER_POSITION.getValue());
                    webSocketRo.setContent(positionMessage);
                    webSocketRo.setState(RoState.WEBSOCKET_SUCCESS.getValue());
                    String replyMessage = JSONObject.toJSONString(webSocketRo);
                    log.info(replyMessage);
                    webSocketChannelMo.getChannel().writeAndFlush(new TextWebSocketFrame(replyMessage));
                }
            }
        }
    }

    /**
     * 向企业管理员发送实时线路上传信息
     */
    public void sendUserKmlLoadMessage(final JSONObject loadProcessMessage, Integer projectId, Integer userId) {
        log.info("WebSocket 推出KML-LOAD进度数据 -> 用户[{}] - {}", userId, loadProcessMessage.getJSONObject("content").toJSONString());
        sendMessageToSomeOneOnline(loadProcessMessage, projectId, userId);
    }

    public void sendMessageToSomeOneOnline(final JSONObject message, Integer projectId, Integer userId) {
        final Optional<Map.Entry<Integer, WebSocketChannelMo>> first = WEB_SOCKET_CHANNEL_MAP.entrySet().stream().filter(entry -> {
            final WebSocketChannelMo channelMo = entry.getValue();
            return channelMo.getProjectId().equals(projectId) && channelMo.getUserId().equals(userId);
        }).findFirst();
        if (first.isPresent()) {
            final WebSocketChannelMo webSocketChannelMo = first.get().getValue();
            webSocketChannelMo.getChannel().writeAndFlush(new TextWebSocketFrame(message.toJSONString()));
        }
    }

    /**
     * 向websocket巡线员用户发送险情处理信息
     *
     * @param map
     */
    public void sendPatrolDangerMessage(final ModelMap map) {
        for (Map.Entry<Integer, WebSocketChannelMo> entry : WEB_SOCKET_CHANNEL_MAP.entrySet()) {
            WebSocketChannelMo webSocketChannelMo = entry.getValue();
            if (map.get("projectId").equals(webSocketChannelMo.getProjectId()) && webSocketChannelMo.getUserId().equals(map.get("inspectorId"))) {
                log.info("WebSocket 推出实时险情标记数据 -> 巡线员[{}]", webSocketChannelMo.getUserId());
                map.remove("inspectorId");
                WebSocketRo<String> webSocketRo = new WebSocketRo<>();
                webSocketRo.setMessageType(WebSocketMessageType.WS_DANGER_LABEL.getValue());
                webSocketRo.setContent(JSONObject.toJSONString(map));
                webSocketRo.setState(RoState.WEBSOCKET_SUCCESS.getValue());
                String replyMessage = JSONObject.toJSONString(webSocketRo);
                webSocketChannelMo.getChannel().writeAndFlush(new TextWebSocketFrame(replyMessage));
            }
        }
    }

    /**
     * APP险情处理完成通知到客户端
     *
     * @param projectId
     * @param dangerId
     */
    public void sendPatrolDealMessage(Integer projectId, Integer dangerId) {
        for (Map.Entry<Integer, WebSocketChannelMo> entry : WEB_SOCKET_CHANNEL_MAP.entrySet()) {
            WebSocketChannelMo webSocketChannelMo = entry.getValue();
            if (webSocketChannelMo.getProjectId().equals(projectId) || webSocketChannelMo.getProjectId() == 0) {
                if (webSocketChannelMo.getRoleId() <= 3) {
                    log.info("WebSocket 推出实时险情处理完成数据 -> 用户[{}]", webSocketChannelMo.getUserId());
                    WebSocketRo<Integer> webSocketRo = new WebSocketRo<>();
                    webSocketRo.setMessageType(WebSocketMessageType.WS_DANGER_DEAL.getValue());
                    webSocketRo.setContent(dangerId);
                    webSocketRo.setState(RoState.WEBSOCKET_SUCCESS.getValue());
                    String replyMessage = JSONObject.toJSONString(webSocketRo);
                    webSocketChannelMo.getChannel().writeAndFlush(new TextWebSocketFrame(replyMessage));
                }
            }
        }
    }

    /**
     * 实时任务直播开始结束通知到客户端
     *
     * @param projectId   项目ID
     * @param source      来源1 云盒 2 御空
     * @param taskId      御空 任务ID 云盒 boxSn
     * @param openOrClose 1开始 0结束
     */
    public void sendTaskVideoLiveMessage(Integer projectId, String source, String taskId, Integer openOrClose) {
        for (Map.Entry<Integer, WebSocketChannelMo> entry : WEB_SOCKET_CHANNEL_MAP.entrySet()) {
            WebSocketChannelMo webSocketChannelMo = entry.getValue();
            if (webSocketChannelMo.getProjectId().equals(projectId) || webSocketChannelMo.getProjectId() == 0) {
                if (webSocketChannelMo.getRoleId() <= 3) {
                    log.info("WebSocket 推出直播状态 -> 用户[{}]", webSocketChannelMo.getUserId());
                    WebSocketRo<JSONObject> webSocketRo = new WebSocketRo<>();
                    webSocketRo.setMessageType(WebSocketMessageType.WS_TASK_LIVE_VIDEO_STATUS.getValue());
                    webSocketRo.setContent(new JSONObject().fluentPut("sourceId", source).fluentPut("taskId", taskId).fluentPut("isLive", openOrClose));
                    webSocketRo.setState(RoState.WEBSOCKET_SUCCESS.getValue());
                    String replyMessage = JSONObject.toJSONString(webSocketRo);
                    log.info(replyMessage);
                    webSocketChannelMo.getChannel().writeAndFlush(new TextWebSocketFrame(replyMessage));
                }
            }
        }
    }

}